package com.opd.soeghtool;

import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.DialogInterface;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

public class BluetoothUtils extends BluetoothGattCallback {

    private final String TAG = "SOE BluetoothUtils";
    public String UpdateServiceUUID="0000fee0-0000-1000-8000-00805f9b34fb";
    public String UpdateCharacterUUID="0000fee1-0000-1000-8000-00805f9b34fb";

    class BLECMD {
        public static final byte CMD_ISP_PROGRAM = (byte) 0x80;
        public static final byte CMD_ISP_ERASE = (byte) 0x81;
        public static final byte CMD_ISP_VERIFY = (byte) 0x82;
        public static final byte CMD_ISP_END = (byte) 0x83;
        public static final byte CMD_ISP_INFO = (byte) 0x84;
        public static final byte CMD_ISP_VERSION =  (byte)0x85;
        public static final byte CMD_ISP_DATE  = (byte)0x86;
        public static final byte CMD_ISP_UNKNOWN  = (byte)0xff;
    }

    private final Context mContext;//service服务
    private static BluetoothUtils bluetoothUtils;
    private BluetoothAdapter bluetoothAdapter;//蓝牙的适配器
    private BluetoothManager bluetoothManager;//蓝牙管理者
    private BluetoothGattService gattService;//通道服务
    private BluetoothGatt bluetoothGatt;
    private BluetoothDevice connectedBluetoothDevice;
    private BluetoothGattCharacteristic mCharIdentify = null;
    private BluetoothGattCharacteristic mCharBlock = null;

    private static final int IAP_LEN = 20;
    private static final int OTA_BLOCK_SIZE = 512;
    byte[] OTATxBuf=new byte[IAP_LEN];
    byte[] mRcvBuffer=new byte[IAP_LEN];
    byte[] g_u8CodeBuf;
    ProgInfo mProgInfo = new ProgInfo();
    String productName ="";
    String strFwVersion="1.001.01";

    private boolean bIsBleConnected = false;
    private boolean bIsRWBusy   = false;

    protected BluetoothUtils(Context context) {
        bluetoothUtils = this;
        this.mContext = context;
        bIsBleConnected =false;
        mProgInfo.reset();
        bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager.getAdapter();
    }

    public void onDestroy() {
        bluetoothUtils = null;
    }

    public boolean connectDevices() {
        Log.d(TAG,"connectDevices");
        if(bluetoothAdapter==null)
            return false;
        if(!bluetoothAdapter.isEnabled())
            return false;
        connectedBluetoothDevice = getConnectDevice(bluetoothAdapter);
        if(connectedBluetoothDevice==null)
            return false;
        BluetoothDevice remoteDevice = bluetoothAdapter.getRemoteDevice(connectedBluetoothDevice.getAddress());
        bluetoothGatt = remoteDevice.connectGatt(mContext, false, this);
        int retry = 100;
        while ((!bIsBleConnected)&&(retry>0))
        {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            retry--;
        }
        return bIsBleConnected;
    }

    public String getBleDeviceName()
    {
        return connectedBluetoothDevice.getName();
    }

    public String getBleProductName()
    {
        return productName;
    }

    public String getBleStrFwVer()
    {
        return strFwVersion;
    }

    public int getBleIntFwVer()
    {
        int ver;
        String[] str1 = strFwVersion.split("\\.");
        ver = Integer.parseInt(str1[0]);
        ver = (ver << 16) + Integer.parseInt(str1[1]);
        ver = (ver << 8) + Integer.parseInt(str1[2]);
        return ver;
    }

    public boolean getBleConnectStatus()
    {
       return bIsBleConnected;
    }

    public int getBleCodeVer()
    {
        int ver=0;
        InputStream is = mContext.getResources().openRawResource(R.raw.mr1_image_a);
        int filelength = 0,fileout=0;
        try {
            filelength = is.available();
            g_u8CodeBuf =  new byte[filelength];
            int count;
            while((count = is.read(g_u8CodeBuf))>0)
            {
                fileout += count;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(fileout==filelength)
        {
            byte temp[] = new byte[8];
            System.arraycopy(g_u8CodeBuf, 0xee0, temp, 0, 8);
            String str = new String(temp);
            Log.d(TAG, str);
            String[] str1 = str.split("\\.");
            ver = Integer.parseInt(str1[0]);
            ver = (ver << 16) + Integer.parseInt(str1[1]);
            ver = (ver << 8) + Integer.parseInt(str1[2]);
        }
        return ver;
    }

    BluetoothDevice getConnectDevice(BluetoothAdapter bluetoothAdapter)
    {
        Class<BluetoothAdapter> bluetoothAdapterClass = BluetoothAdapter.class;//得到BluetoothAdapter的Class对象
        try {//得到蓝牙状态的方法
            Method method = bluetoothAdapterClass.getDeclaredMethod("getConnectionState", (Class[]) null);
            //打开权限
            method.setAccessible(true);
            int state = (int) method.invoke(bluetoothAdapter, (Object[]) null);
            if(state == BluetoothAdapter.STATE_CONNECTED){
                Log.i(TAG,"BluetoothAdapter.STATE_CONNECTED");
                Set<BluetoothDevice> devices = bluetoothAdapter.getBondedDevices();
                Log.i(TAG,"devices:"+devices.size());
                for(BluetoothDevice device : devices){
                    Method isConnectedMethod = BluetoothDevice.class.getDeclaredMethod("isConnected", (Class[]) null);
                    method.setAccessible(true);
                    boolean isConnected = (boolean) isConnectedMethod.invoke(device, (Object[]) null);
                    if(isConnected){
                        Log.i(TAG,"connected:"+device.getAddress());
                        Log.i(TAG,"connected:"+device.getName());
                        // return device.getAddress();
                        return device;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //连接状态变化时回调
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);

        if(newState == BluetoothProfile.STATE_CONNECTED){  // 连接成功状态
            //连接成功之后的操作
            gatt.discoverServices();// 发现蓝牙服务
        }else if(newState == BluetoothProfile.STATE_DISCONNECTED){ // 断开连接状态
            //断开连接之后的操作
            //Toast.makeText(MainActivity.this,"蓝牙连接已断开！",Toast.LENGTH_SHORT).show();
            mCharBlock = null;
            mCharIdentify = null;
            bluetoothGatt = null;
            bIsBleConnected = false;
            Log.d(TAG, "蓝牙连接已断开！");
        }
    }

    //发现蓝牙服务，在蓝牙连接的时候会调用
    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        super.onServicesDiscovered(gatt, status);
        if (status == BluetoothGatt.GATT_SUCCESS) { // 发现蓝牙服务成功
            List<BluetoothGattService> gattServicesList = gatt.getServices();
            for (BluetoothGattService service:gattServicesList) {
                Log.d(TAG, "gattServicesList UUID=" + service.getUuid());
                if(service.getUuid().toString().equalsIgnoreCase(UpdateServiceUUID)){
                    for (BluetoothGattCharacteristic characteristic:service.getCharacteristics()) {
                        String s=characteristic.getUuid().toString();
                        if(s.equalsIgnoreCase(UpdateCharacterUUID)){
                            mCharIdentify=characteristic;
                            mCharBlock=characteristic;
                            bIsBleConnected =  true;
                            //Toast.makeText(MainActivity.this,"已连接到蓝牙设备！",Toast.LENGTH_SHORT).show();
                            Log.d(TAG, "已连接到蓝牙设备！");
                        }
                    }
                }
            }
        } else {
            Log.e(TAG, "当前状态:" + status);
        }
    }

    // 当接收到数据时
    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicRead(gatt, characteristic, status);
        int rcvLength;
        if (status == BluetoothGatt.GATT_SUCCESS) { // 接收数据成功时
            //Log.e(TAG, "onCharacteristicRead:" + status);
            if(characteristic.getValue()==null)
            {
                bIsRWBusy = false;
                mRcvBuffer = null;
                return;
            }
            rcvLength = characteristic.getValue().length;
            System.arraycopy(characteristic.getValue(), 0,
                    mRcvBuffer, 0, rcvLength);
            bIsRWBusy = false;
        }
    }

    //当开始写入数据时
    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);
        if (status == BluetoothGatt.GATT_SUCCESS) { // 写入数据成功时
            //Log.e(TAG, "onCharacteristicWrite:" + status);
            bIsRWBusy = false;
        }
    }

    //当特征值发生变化时
    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);

    }

    //当传输最大数据包大小发生变化时
    @Override
    public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
        super.onMtuChanged(gatt, mtu, status);
        if (status == BluetoothGatt.GATT_SUCCESS) { // 修改最大传输数据包值成功
            Log.e(TAG, "onMtuChanged:" + status);
        }
    }

    public boolean gattWriteCharacteristic(BluetoothGattCharacteristic btgCharacter,byte[] data)
    {
        int retry = 50000;
        if(mCharIdentify==null)
        {
            return false;
        }
        btgCharacter.setValue(data);
        bIsRWBusy = true;
        boolean success = bluetoothGatt.writeCharacteristic(btgCharacter);
        if(success)
        {
            while (bIsRWBusy&&(retry>0))
            {
                try {
                    Thread.sleep(0,20000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                retry--;
            }
            return  true;
        }
        return  false;
    }

    public boolean gattWriteCharacteristicNoRep(BluetoothGattCharacteristic btgCharacter,byte[] data)
    {
        if(mCharIdentify==null)
        {
            Toast.makeText(mContext,"特征不存在",Toast.LENGTH_SHORT).show();
            return false;
        }
        btgCharacter.setValue(data);
        return  bluetoothGatt.writeCharacteristic(btgCharacter);
    }

    public boolean gattReadCharacteristic(BluetoothGattCharacteristic btgCharacter)
    {
        int retry = 50000;
        if(btgCharacter==null)
        {
            Toast.makeText(mContext,"特征不存在",Toast.LENGTH_SHORT).show();
            return false;
        }
        bIsRWBusy = true;
        boolean success = bluetoothGatt.readCharacteristic(btgCharacter);
        if(success)
        {
            while (bIsRWBusy&&(retry>0))
            {
                try {
                    Thread.sleep(0,20000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                retry--;
            }
            return (mRcvBuffer!=null);
        }
        return false;
    }

    private class ProgInfo {
        int iBytes = 0; // Number of bytes programmed
        int nBytes = 0; // Total number of bytes
        short iBlocks = 0; // Number of blocks programmed
        short nBlocks = 0; // Total number of blocks
        int startAddr = 0;
        int offset = 0;
        int iTimeElapsed = 0; // Time elapsed in milliseconds
        Character imgType ='N';
        void reset() {
            iBytes = 0;
            iBlocks = 0;
            iTimeElapsed = 0;
            imgType = 'N';
            nBytes = 0;
            nBlocks = 0;
            offset = 0;
            startAddr = 0;
        }
    }

    void getDeviceInfo() {
        if(mCharBlock==null || mCharIdentify==null){
            Log.d(TAG,"characteristic are null");
            return;
        }
        byte[] sndbuf = new byte[IAP_LEN - 2];

        sndbuf[0] = BLECMD.CMD_ISP_INFO;
        sndbuf[1] = IAP_LEN - 2;
        Log.d(TAG,"getInfo");
        boolean success =gattWriteCharacteristic(mCharIdentify,sndbuf);
        if(success)
        {
            if(gattReadCharacteristic(mCharIdentify))
            {
                if (mRcvBuffer[0] == BLECMD.CMD_ISP_INFO)
                {
                    if (mRcvBuffer[2] == 0x01) {
                        //Log.d(TAG, "当前状态: Image A");
                        mProgInfo.imgType = 'A';
                    } else if (mRcvBuffer[2] == 0x02) {
                        //Log.d(TAG, "当前状态: Image B");
                        mProgInfo.imgType = 'B';
                    }
                    mProgInfo.offset = ByteDataUtils.bytesToIntLSB(mRcvBuffer, 3);
                    byte[] name = new byte[4];
                    System.arraycopy(mRcvBuffer, 9, name, 0, 4);
                    String str = new String(name);
                    productName = str;
                    //Log.d(TAG, "当前设备:" + str);
                }
                else
                {
                    mProgInfo.imgType = 'N';
                    mProgInfo.offset = 0x1F400;
                }
            }
        }
    }

    void getDeviceVersion() {
        if(mCharBlock==null || mCharIdentify==null){
            Log.d(TAG,"characteristic are null");
            return;
        }
        byte[] sndbuf = new byte[IAP_LEN - 2];

        sndbuf[0] = BLECMD.CMD_ISP_VERSION;
        sndbuf[1] = IAP_LEN - 2;
        Log.d(TAG,"getVersion");
        boolean success =gattWriteCharacteristic(mCharIdentify,sndbuf);
        if(success)
        {
            if(gattReadCharacteristic(mCharIdentify))
            {
                if(mRcvBuffer[0]==BLECMD.CMD_ISP_VERSION)
                {
                    byte[] name = new byte[8];
                    System.arraycopy(mRcvBuffer, 2, name, 0, 8);
                    String str = new String(name);
                    //Log.d(TAG,bytesToHexString(name));
                    Log.d(TAG, "当前版本:" + str);
                    strFwVersion = str;
                    //Log.d(TAG,String.format("%x,%x,%x,%x,%x,",name[2],name[3],name[4],name[5],name[6]));
                }
            }
        }
    }

    void getDeviceCodeDate() {
        if(mCharBlock==null || mCharIdentify==null){
            Log.d(TAG,"getTargetImageInfo shouldn't work ,two characteristic are null");
            return;
        }
        byte[] sndbuf = new byte[IAP_LEN - 2];
        sndbuf[0] = BLECMD.CMD_ISP_DATE;
        sndbuf[1] = IAP_LEN - 2;
        Log.d(TAG,"getDate");
        boolean success =gattWriteCharacteristic(mCharIdentify,sndbuf);
        if(success)
        {
            if(gattReadCharacteristic(mCharIdentify))
            {
                if(mRcvBuffer[0]==BLECMD.CMD_ISP_DATE)
                {
                    byte[] name = new byte[14];
                    System.arraycopy(mRcvBuffer, 2, name, 0, 14);
                    String str = new String(name);
                    Log.d(TAG, "发布日期:" + str);
                }
            }
        }
    }

    public boolean loadBinFile(int type)
    {
        InputStream is = null;
        int filelength = 0,fileout=0;
        if(0x01==type)
        {
            is = mContext.getResources().openRawResource(R.raw.mr1_image_a);
        }
        else if(0x02==type)
        {
            is = mContext.getResources().openRawResource(R.raw.mr1_image_b);
        }
        else
        {
            return false;
        }

        try {
            filelength = is.available();
            g_u8CodeBuf =  new byte[filelength];
            int count;
            while((count = is.read(g_u8CodeBuf))>0)
            {
                fileout += count;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        Log.d(TAG, "LoadCode: get="+String.valueOf(filelength)+" Read:" +String.valueOf(fileout));

        if(filelength==fileout)
        {
            int offset = ByteDataUtils.bytesToIntLSB(g_u8CodeBuf,4);
            if(((offset<mProgInfo.offset)&&(mProgInfo.imgType=='B'))||((offset>mProgInfo.offset)&&(mProgInfo.imgType=='A')))
            {
                //g_mCodeLength = filelength;
                mProgInfo.nBytes = filelength;
                mProgInfo.nBlocks = (short) ((filelength + OTA_BLOCK_SIZE - 1) / OTA_BLOCK_SIZE);
                if(mProgInfo.imgType=='A')
                    mProgInfo.startAddr = 0x1F400;
                else
                    mProgInfo.startAddr = 0;
               Log.d(TAG,"mProgInfo.iBlocks: "+mProgInfo.iBlocks+" mProgInfo.nBlocks: "+mProgInfo.nBlocks);
                return true;
            }
        }
        return false;
    }

    // Erase
    public boolean eraseFlash(OnUpdateListener listener)
    {
        listener.onUpdateStage(OTA_STAGE.OTA_STA_ERASE);
        if (mProgInfo.iBlocks < mProgInfo.nBlocks) {
            listener.onUpdating(0,mProgInfo.nBlocks);
            //byte [] outBuffer = new byte[6];
            Arrays.fill(OTATxBuf, (byte) 0x00);
            // Prepare block
            OTATxBuf[0] = BLECMD.CMD_ISP_ERASE;
            OTATxBuf[1] = 0x00;
            OTATxBuf[2] = (byte) (mProgInfo.startAddr / 4);
            OTATxBuf[3] = (byte) ((mProgInfo.startAddr / 4) >> 8);
            OTATxBuf[4] = (byte) mProgInfo.nBlocks;
            OTATxBuf[5] = (byte) (mProgInfo.nBlocks >> 8);
            // Send block
            boolean success = gattWriteCharacteristic(mCharBlock, OTATxBuf);
            if (success) {
                for (int i = 0; i < 50; i++) {
                    success = gattReadCharacteristic(mCharBlock);
                    if (success) {
                        Log.d(TAG,String.format("l=%d,%x,%x",mRcvBuffer.length,mRcvBuffer[0],mRcvBuffer[2]));
                        if((mRcvBuffer.length!=0)&&(mRcvBuffer[0]==BLECMD.CMD_ISP_ERASE))
                        {
                            if(mRcvBuffer[2] == 0x00)
                            {
                                mProgInfo.iBlocks = mProgInfo.nBlocks;
                                listener.onUpdating(mProgInfo.iBlocks,mProgInfo.nBlocks);
                                return true;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    // Program
    public boolean programFlash(OnUpdateListener listener)
    {
        boolean halfPack = false;
        listener.onUpdateStage(OTA_STAGE.OTA_STA_PROGRAM);
        listener.onUpdating(0,mProgInfo.nBytes);
        for(mProgInfo.iBytes=0;mProgInfo.iBytes < mProgInfo.nBytes;)
        {
            if(!bIsBleConnected)
                return false;
            if ((mProgInfo.nBytes - mProgInfo.iBytes) < IAP_LEN - 4)
                halfPack = true;
            //byte []buffer =new byte[IAP_LEN];
            Arrays.fill(OTATxBuf, (byte) 0x00);
            OTATxBuf[0] = BLECMD.CMD_ISP_PROGRAM;
            OTATxBuf[1] = IAP_LEN - 4;
            OTATxBuf[2] = (byte) ((mProgInfo.iBytes + mProgInfo.startAddr) / 4);
            OTATxBuf[3] = (byte) (((mProgInfo.iBytes + mProgInfo.startAddr) / 4) >> 8);
            if (halfPack)
                System.arraycopy(g_u8CodeBuf, mProgInfo.iBytes,
                        OTATxBuf, 4, mProgInfo.nBytes - mProgInfo.iBytes);
            else
                System.arraycopy(g_u8CodeBuf, mProgInfo.iBytes,
                        OTATxBuf, 4, IAP_LEN - 4);

            boolean success = gattWriteCharacteristicNoRep(mCharBlock, OTATxBuf);
            if (success) {
                if (halfPack)
                    mProgInfo.iBytes = mProgInfo.nBytes;
                else
                    mProgInfo.iBytes += IAP_LEN - 4;
                //progressDialog.setProgress((mProgInfo.iBytes * 100) / mProgInfo.nBytes);
                listener.onUpdating(mProgInfo.iBytes,mProgInfo.nBytes);
            }
        }
        Log.d(TAG,String.format("total= %d,now= %d",mProgInfo.nBytes,mProgInfo.iBytes));
        return (mProgInfo.nBytes==mProgInfo.iBytes);
    }

    public boolean verifyFlash(OnUpdateListener listener)
    {
        boolean halfPack = false;
        boolean lastPack = false;
        listener.onUpdateStage(OTA_STAGE.OTA_STA_VERIFY);
        listener.onUpdating(0,mProgInfo.nBytes);
        for(mProgInfo.iBytes=0;mProgInfo.iBytes < mProgInfo.nBytes;)
        {
            if(!bIsBleConnected)
                return false;
            if ((mProgInfo.nBytes - mProgInfo.iBytes) < IAP_LEN - 4)
                halfPack = true;

            if ((mProgInfo.nBytes - mProgInfo.iBytes) <= IAP_LEN - 4)
                lastPack = true;
            //byte []buffer = new byte[IAP_LEN];
            Arrays.fill(OTATxBuf, (byte) 0x00);

            OTATxBuf[0] = BLECMD.CMD_ISP_VERIFY;
            OTATxBuf[1] = IAP_LEN - 4;
            OTATxBuf[2] = (byte) ((mProgInfo.iBytes + mProgInfo.startAddr) / 4);
            OTATxBuf[3] = (byte) (((mProgInfo.iBytes + mProgInfo.startAddr) / 4) >> 8);
            if (halfPack)
                System.arraycopy(g_u8CodeBuf, mProgInfo.iBytes,
                        OTATxBuf, 4, mProgInfo.nBytes - mProgInfo.iBytes);
            else
                System.arraycopy(g_u8CodeBuf, mProgInfo.iBytes,
                        OTATxBuf, 4, IAP_LEN - 4);

            // Send block
            boolean success = gattWriteCharacteristic(mCharBlock, OTATxBuf);
            if (success) {
                if (lastPack) {
                    success = gattReadCharacteristic(mCharBlock);
                    if (success) {
                        if((mRcvBuffer.length != 0) && (mRcvBuffer[0] == BLECMD.CMD_ISP_VERIFY)&&(mRcvBuffer[2] == 0x00))
                        {
                            if (halfPack)
                                mProgInfo.iBytes = mProgInfo.nBytes;
                            else
                                mProgInfo.iBytes += IAP_LEN - 4;
                            //progressDialog.setProgress((mProgInfo.iBytes * 100) / mProgInfo.nBytes);
                            listener.onUpdating(mProgInfo.iBytes,mProgInfo.nBytes);
                        }
                        else
                        {
                            Log.d(TAG, String.format("Verify Fail!=%d,=%x,%x", mRcvBuffer.length, mRcvBuffer[0],mRcvBuffer[2]));
                            //progressDialog.setMessage("升级失败");
                            return false;
                        }
                    }
                } else {
                    if (halfPack)
                        mProgInfo.iBytes = mProgInfo.nBytes;
                    else
                        mProgInfo.iBytes += IAP_LEN - 4;
                    //progressDialog.setProgress((mProgInfo.iBytes * 100) / mProgInfo.nBytes);
                    listener.onUpdating(mProgInfo.iBytes,mProgInfo.nBytes);
                }
            }
        }
        Log.d(TAG,String.format("total= %d,now= %d",mProgInfo.nBytes,mProgInfo.iBytes));
        return (mProgInfo.nBytes==mProgInfo.iBytes);
    }

    private boolean endIsp(OnUpdateListener listener) {
        // Prepare block
        byte []buffer = new byte[IAP_LEN];
        buffer[0] = BLECMD.CMD_ISP_END;
        buffer[1] = IAP_LEN - 2;
        boolean success = gattWriteCharacteristic(mCharBlock, buffer);
        if (success) {
            listener.onUpdateStage(OTA_STAGE.OTA_STA_COMPLETE);
            Log.d(TAG,"OTA Update Complete!\n");
            return true;
        }
        Log.d(TAG,"OTA Update failed!\n");
        return false;
    }

    public class OTA_STAGE
    {
        final static int OTA_STA_LOAD_FILE = 0;
        final static int OTA_STA_GET_INFO = 1;
        final static int OTA_STA_ERASE = 2;
        final static int OTA_STA_PROGRAM = 3;
        final static int OTA_STA_VERIFY = 4;
        final static int OTA_STA_COMPLETE = 5;
    };


    public void OTAUpdateFw(final OnUpdateListener listener)
    {
        if(mCharBlock==null || mCharIdentify==null||(bluetoothGatt==null)){
            Log.d(TAG,"BLE not connect or characteristic are null");
            return;
        }
        new Thread()
        {
            public void run()
            {
                listener.onUpdateStage(OTA_STAGE.OTA_STA_GET_INFO);
                listener.onUpdating(1,100);
                getDeviceInfo();
                listener.onUpdateStage(OTA_STAGE.OTA_STA_LOAD_FILE);
                if(mProgInfo.imgType=='A')
                    loadBinFile(0x02);
                else if(mProgInfo.imgType=='B')
                    loadBinFile(0x01);
                else
                {
                    listener.onUpdateStage(OTA_STAGE.OTA_STA_LOAD_FILE);
                    listener.onUpdateError(-1);
                    return;
                }
                if(!eraseFlash(listener))
                {
                    listener.onUpdateStage(OTA_STAGE.OTA_STA_ERASE);
                    listener.onUpdateError(-1);
                    return;
                }
                mProgInfo.iBytes = 0;
                while(mProgInfo.iBytes < mProgInfo.nBytes) {
                    if(!programFlash(listener)) {
                        listener.onUpdateStage(OTA_STAGE.OTA_STA_PROGRAM);
                        listener.onUpdateError(-1);
                        return;
                    }
                }
                mProgInfo.iBytes = 0;
                while(mProgInfo.iBytes < mProgInfo.nBytes) {
                        if(!verifyFlash(listener)) {
                            listener.onUpdateStage(OTA_STAGE.OTA_STA_VERIFY);
                            listener.onUpdateError(-1);
                            return;
                    }
                }
                endIsp(listener);
            }
        }.start();
    }

    public interface OnUpdateListener {
        void onUpdateError(int e);
        void onUpdating(int progress,long total);
        void onUpdateStage(int stage);
    }
}
